/*
 * Copyright ©2021 su binglun(9085309@qq.com). All rights reserved.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
 *---------------------------------------------------------------------
 *-                                                                   -
 *-           Website : http://phoenix.sunny360.cn/                   -
 *-                                                                   -
 *---------------------------------------------------------------------
 */
package cn.sunny360.core.service.impl;

import cn.sunny360.core.common.PhResult;
import cn.sunny360.core.service.LinkmanService;
import cn.sunny360.core.utils.Container;
import cn.sunny360.core.utils.JsonUtil;
import cn.sunny360.core.wrapper.CacheWrapper;
import cn.sunny360.core.wrapper.DBWrapper;
import com.sohu.idcenter.IdWorker;
import io.vertx.core.Promise;
import io.vertx.core.impl.logging.Logger;
import io.vertx.core.impl.logging.LoggerFactory;
import io.vertx.core.json.JsonArray;
import io.vertx.core.json.JsonObject;
import io.vertx.sqlclient.Tuple;

import java.time.LocalDateTime;
import java.util.Date;
import java.util.List;

/**
 * implementation of {@link LinkmanService}.
 *
 * @author sublun
 */
public class LinkmanServiceImpl implements LinkmanService {

	private static final Logger logger = LoggerFactory.getLogger(LinkmanServiceImpl.class);

	private IdWorker idWorker;
	private DBWrapper dbWrapper;
	private CacheWrapper cacheWrapper;

	public LinkmanServiceImpl() {
		idWorker = Container.getComponent(IdWorker.class);
		dbWrapper = Container.getComponent(DBWrapper.class);
		cacheWrapper = Container.getComponent(CacheWrapper.class);
	}

	@Override
	public LinkmanServiceImpl getLinkmanList(Long userId, Promise<JsonArray> handler) {
		dbWrapper.findList(
				"SELECT\n" +
						"	a.linkman_id,\n" +
						"	a.username,\n" +
						"	a.nick_name,\n" +
						"	a.avatar,\n" +
						"	a.sex,\n" +
						"	a.link_time,\n" +
						"	a.linkman_alias,\n" +
						"  IF( b.user_id IS NULL, 0, 1 ) online_status \n" +
						"FROM\n" +
						"	ph_user_linkman a\n" +
						"	LEFT JOIN ph_online b ON a.linkman_id = b.user_id \n" +
						"WHERE\n" +
						"	a.owner_id = ? \n" +
						"ORDER BY\n" +
						"	online_status DESC,\n" +
						"	a.link_time", Tuple.of(userId))
				.future()
				.onFailure(handler::fail)
				.onSuccess(list->{
					handler.complete(JsonUtil.toStrVal(new JsonArray(list)));
				});
		return this;
	}

	@Override
	public LinkmanServiceImpl addLinkman(Long userId, Long linkmanId, Promise<String> handler) {
		//判断联系人是否存在
		dbWrapper.findOne("select * from ph_user_linkman where owner_id=? and linkman_id=?", Tuple.of(userId, linkmanId))
				.future()
				.onFailure(handler::fail)
				.onSuccess(optional->{
					//如果查询到数据说明联系人已经存在。
					if (optional.isPresent()) {
						handler.fail("联系人已经存在，不要重复添加");
						return;
					}
					//添加联系人
					//根据id查询联系人信息
					dbWrapper.findOne("select user_id,username,nick_name,sex,head_img from ph_user where user_id = ?", Tuple.of(linkmanId))
							.future()
							.onFailure(handler::fail)
							.onSuccess(o->{
								if(!o.isPresent()) {
									handler.fail("联系人：“"+linkmanId+"”不存在!");
									return;
								}
								JsonObject jsonObject = o.get();
								//添加联系人
								dbWrapper.insert("INSERT INTO ph_user_linkman " +
												"( id, owner_id, linkman_id, username, nick_name, avatar,sex, link_time ) " +
												"VALUES(?,?,?,?,?,?,?)",
										Tuple.of(idWorker.getId(),
												userId,
												linkmanId,
												jsonObject.getString("username"),
												jsonObject.getString("nick_name"),
												jsonObject.getLong("head_img"),
												jsonObject.getInteger("sex"),
												LocalDateTime.now()
										))
										.future()
										.onFailure(handler::fail)
										.onSuccess(h->handler.complete("OK"));
							});
				});

		return this;
	}

	@Override
	public LinkmanServiceImpl removeLinkman(Long userId, Long linkmanId, Promise<String> handler) {
		dbWrapper.delete("delete from ph_user_linkman where owner_id=? and linkman_id=?", Tuple.of(userId, linkmanId))
				.future()
				.onFailure(handler::fail)
				.onSuccess(o->handler.complete("OK"));
		return this;
	}

	@Override
	public LinkmanServiceImpl updateLinkTime(Long userId, Long linkmanId, Promise<String> handler) {

		dbWrapper.update("update ph_user_linkman set link_time=? where owner_id = ? and linkman_id=?"
				, Tuple.of(
						new Date(),
						userId,
						linkmanId
				))
				.future()
				.onFailure(handler::fail)
				.onSuccess(h->handler.complete("OK"));

		return this;
	}

	@Override
	public LinkmanService applyLinkman(Long masterId, Long applyUserId, String source, String comment, String ownerAlias, Promise<PhResult> handler) {
		dbWrapper.findOne("select count(*) count from ph_linkman where owner_id = ? and linkman_id = ?",
				Tuple.of(masterId, applyUserId))
				.future()
				.onFailure(handler::fail)
				.onSuccess(o->{
					Integer count = o.get().getInteger("count");
					//联系人已经存在
					if (count > 0) {
						handler.complete(PhResult.result(400, "联系人已经存在", ""));
						return;
					}
					long applyId = idWorker.getId();
					dbWrapper.findOne("select * from ph_user where user_id = ?",
									Tuple.of(applyUserId))
							.future()
							.onFailure(handler::fail)
							.onSuccess(optional->{
								JsonObject applyUser = optional.get();
								dbWrapper.insert(
									"insert into ph_linkman_apply(\n" +
										"  apply_id,\n" +
										"  owner_id,\n" +
										"  linkman_id,\n" +
										"  username,\n" +
										"  nick_name,\n" +
										"  head_img,\n" +
										"  source,\n" +
										"  comment,\n" +
										"  owner_alias,\n" +
										"  feed_status,\n" +
										"  feed_comment\n" +
										") values (\n" +
										"  ?,?,?,?,?,\n" +
										"  ?,?,?,?\n" +
										")\n", Tuple.of(
											applyId,
											masterId,
											applyUserId,
											applyUser.getString("username"),
											applyUser.getString("nick_name"),
											applyUser.getString("head_img"),
											source,
											comment,
											ownerAlias,
											0,
											null
										)).future()
										.onFailure(handler::fail)
										.onSuccess(h->handler.complete(PhResult.ok("OK", applyId + "")));
							});

				});
		return this;
	}

	@Override
	public LinkmanService getApplyList(Long userId, Promise<List<JsonObject>> handler) {
		dbWrapper.findList("select * from ph_linkman_apply where owner_id = ?", Tuple.of(userId))
				.future()
				.onFailure(handler::fail)
				.onSuccess(handler::complete);
		return this;
	}

	@Override
	public LinkmanService feedApply(Long applyId, Integer feedStatus, String feedComment, String alias, Promise<PhResult> handler) {
		if (1 == feedStatus) {
			handler = acceptApply(applyId, feedStatus, feedComment, alias);
		} else {
			handler = rejectApply(applyId, feedStatus, feedComment);
		}
		return this;
	}

	private Promise<PhResult> acceptApply(Long applyId, Integer feedStatus, String feedComment, String alias) {
		Promise<PhResult> promise = Promise.promise();
		dbWrapper.findOne("SELECT\n" +
						"  a.*,\n" +
						"  b.username o_username,\n" +
						"  b.nick_name o_nick_name,\n" +
						"  b.head_img o_head_img \n" +
						"FROM\n" +
						"  ph_linkman_apply a\n" +
						"  JOIN ph_user b ON a.owner_id = b.user_id \n" +
						"WHERE\n" +
						"  apply_id = ?", Tuple.of(applyId))
				.future()
				.onFailure(promise::fail)
				.onSuccess(o->{
					JsonObject applyInfo = o.get();
					dbWrapper.executeWithTrans(
							new DBWrapper.SQLTuple("update ph_linkman_apply set feed_status = ?, feed_comment = ? where apply_id = ?",
									Tuple.of(feedStatus, feedComment, applyId)),
							new DBWrapper.SQLTuple("INSERT INTO ph_user_linkman " +
									"( id, owner_id, linkman_id, username, nick_name, avatar, link_time,linkman_alias ) " +
									"VALUES(?,?,?,?,?,?,?)",
									Tuple.of(idWorker.getId(),
											applyInfo.getLong("owner_id"),
											applyInfo.getLong("linkman_id"),
											applyInfo.getString("username"),
											applyInfo.getString("nick_name"),
											applyInfo.getLong("head_img"),
											LocalDateTime.now(),
											alias
									)),
							new DBWrapper.SQLTuple("INSERT INTO ph_user_linkman " +
									"( id, owner_id, linkman_id, username, nick_name, avatar, link_time,linkman_alias ) " +
									"VALUES(?,?,?,?,?,?,?)",
									Tuple.of(idWorker.getId(),
											applyInfo.getLong("linkman_id"),
											applyInfo.getLong("owner_id"),
											applyInfo.getString("o_username"),
											applyInfo.getString("o_nick_name"),
											applyInfo.getLong("o_head_img"),
											LocalDateTime.now(),
											applyInfo.getString("owner_alias")
							)))
							.future()
							.onFailure(promise::fail)
							.onSuccess(h->promise.complete(PhResult.ok()));
				});
		return promise;
	}

	private Promise<PhResult> rejectApply(Long applyId, Integer feedStatus, String feedComment) {
		Promise<PhResult> promise = Promise.promise();
		dbWrapper.update("update ph_linkman_apply set feed_status = ?, feed_comment = ? where apply_id = ?",
				Tuple.of(feedStatus, feedComment, applyId))
				.future()
				.onFailure(promise::fail)
				.onSuccess(h->promise.complete(PhResult.ok()));
		return promise;
	}


}